package tests.suite.tests
{
	import com.gdcnano.nanoamp.media.sound.playlist.AbstractPlaylist;
	import com.gdcnano.nanoamp.media.sound.playlist.IPlaylist;
	import com.gdcnano.nanoamp.media.sound.playlist.ITrack;
	import com.gdcnano.nanoamp.media.sound.playlist.Track;
	
	import flash.events.Event;
	
	import flexunit.framework.Assert;
	
	import org.flexunit.async.Async;

	public class PlaylistTestCase
	{
		private static const ASYNC_TIME:int = 30;
		
		private var _playlist:IPlaylist;
		
		private var _track1:ITrack = createTrack("Ben E. King", "Stand By Me / On the Horizon", "Stand By Me", "http://example.com/beneking/StandByMe");
		private var _track2:ITrack = createTrack("Queen", "A Night at the Opera", "Bohemian Rhapsody", "http://example.com/queen/BohemianRhapsody");
		private var _track3:ITrack = createTrack("Simon & Garfunkel", "Bridge Over Troubled Water", "Bridge Over Troubled Water", "http://example.com/SimonGarfunkel/BridgeOverTroubledWater");
		private var _trackWhichIsNotInPlaylist:ITrack = createTrack("Руки вверх", "Сделай погромче!", "Крошка моя", "http://example.com/");
		
		public function PlaylistTestCase()
		{
			_playlist = new AbstractPlaylist();
		}
		
		[Before]
		public function setup():void
		{
			fillPlaylist();
		}
		
		[Test(async)]
		public function canAddRemoveTracks():void
		{
			// Clear playlist to avoid changes from #setup()
			_playlist.clear();
			// Check if playlist is empty
			Assert.assertTrue(_playlist.tracklist.length == 0);

			// Add a track to playlist
			_playlist.addTrack(_track1);
			// Check that playlist now contains one track
			Assert.assertTrue(_playlist.tracklist.length == 1);
			
			// Add another track
			_playlist.addTrack(_track2);
			// Check them
			Assert.assertTrue(_playlist.tracklist.length == 2);
			
			// And yet another one
			_playlist.addTrack(_track3);
			// Check again
			Assert.assertTrue(_playlist.tracklist.length == 3);
			
			// Now let's remove track
			_playlist.removeTrack(_track3);
			// Count of tracks shoulld be reduced
			Assert.assertTrue(_playlist.tracklist.length == 2);
			
			(_playlist as AbstractPlaylist).addEventListener(AbstractPlaylist.TRACK_NOT_IN_PLAYLIST, Async.asyncHandler(this, handleTrackNotInplaylist, ASYNC_TIME, _trackWhichIsNotInPlaylist, handleTimeout));
			
			// Try to remove track which is not in the playlist
			// @see #handleTrackNotInplaylist()
			_playlist.removeTrack(_trackWhichIsNotInPlaylist);
			// Count of track should still be 2
			Assert.assertTrue(_playlist.tracklist.length == 2);
			
			// Let's clear playlist again
			_playlist.clear();
			// Check if playlist is empty
			Assert.assertTrue(_playlist.tracklist.length == 0);
		}
		
		[Test(async)]
		public function canSetCurrentTrack():void
		{
			// Set current track
			_playlist.currentTrack = _track1;
			// Check if the proper track was selected as current
			Assert.assertEquals(_playlist.currentTrack, _track1);
			// Check that first track was selected
			Assert.assertEquals(_playlist.currentTrackIndex, 0);
			
			(_playlist as AbstractPlaylist).addEventListener(AbstractPlaylist.TRACK_NOT_IN_PLAYLIST, Async.asyncHandler(this, handleTrackNotInplaylist, ASYNC_TIME, _trackWhichIsNotInPlaylist, handleTimeout));
			// Try to set as current track which is not in the playlist
			_playlist.currentTrack = _trackWhichIsNotInPlaylist;
			// Current track should still be _track1
			Assert.assertEquals(_playlist.currentTrack, _track1);
			
			// Select track3 as currentTrack
			_playlist.currentTrack = _track3;
			// Check if the proper track was selected as current
			Assert.assertEquals(_playlist.currentTrack, _track3);
			// Check that first track was selected
			Assert.assertEquals(_playlist.currentTrackIndex, 2);
			
			(_playlist as AbstractPlaylist).addEventListener(AbstractPlaylist.TRACKLIST_IS_EMPTY, Async.asyncHandler(this, handleTrackListIsEmpty, ASYNC_TIME, _track1, handleTimeout));
			// Now try to clear tracklist
			_playlist.clear();
			// and set currentTrack property
			_playlist.currentTrack = _track1;
			// Current track should be null and the event should be dispathced
			// @see #handleTrackListIsEmpty()
			Assert.assertNull(_playlist.currentTrack);
			
			/*
			// Direct assignment to the not using setter 
			// (which is used only for binding porposes)
			_playlist.currentTrackIndex = 3;
			// Shouldn't change statement
			Assert.assertEquals(_playlist.currentTrackIndex, 2);*/
		}
		
		[Test]
		public function canSelectNextTrack():void
		{
			// Check track1 as current track
			_playlist.currentTrack = _track1;
			
			// If current track is the first track in collection and collection has 
			// more than one track, then canPlayNextTrack should be true
			Assert.assertTrue(_playlist.canPlayNextTrack);
			
			// Switch to next track
			_playlist.nextTrack();
			// Now currentTrack property should contain track2
			Assert.assertEquals(_playlist.currentTrack, _track2);
			// We still can play next track
			Assert.assertTrue(_playlist.canPlayNextTrack);
			
			// Switch to next track
			_playlist.nextTrack();
			// Now we are on track3…
			Assert.assertEquals(_playlist.currentTrack, _track3);
			// … and at the end of tracklist
			Assert.assertFalse(_playlist.canPlayNextTrack);
			
			// Try to switch to the next track one more time
			_playlist.nextTrack();
			// Current track should still be track3 
			Assert.assertEquals(_playlist.currentTrack, _track3);
			// We still can't play next track
			Assert.assertFalse(_playlist.canPlayNextTrack);
			/*
			// Direct assignment to the not using setter 
			// (which is used only for binding porposes)
			_playlist.canPlayNextTrack = true;
			// Shouldn't change statement
			Assert.assertFalse(_playlist.canPlayNextTrack);*/
		}

		[Test]
		public function canSelectPreviousTrack():void
		{
			// Check track1 as current track
			_playlist.currentTrack = _track1;
			// As current track is the first track in collection
			// than previous track could not be selected
			Assert.assertFalse(_playlist.canPlayPreviousTrack);
			
			// Ok, then let's select last track in tracklist
			_playlist.currentTrack = _track3;
			// So now should be available to swith to previous track
			Assert.assertTrue(_playlist.canPlayPreviousTrack);
			
			// Ok, let's select previous
			_playlist.previousTrack();
			// It should be track3
			Assert.assertEquals(_playlist.currentTrack, _track2);
			Assert.assertTrue(_playlist.canPlayPreviousTrack);
			
			// One more time
			_playlist.previousTrack();
			// Well, here we at the beginning of our tracklist again
			Assert.assertEquals(_playlist.currentTrack, _track1);
			Assert.assertFalse(_playlist.canPlayPreviousTrack);
			
			// Try to switch to the previous track again
			_playlist.previousTrack();
			// The statement should be the same
			Assert.assertEquals(_playlist.currentTrack, _track1);
			Assert.assertFalse(_playlist.canPlayPreviousTrack);
			
			
			
			/*
			// Direct assignment to the not using setter 
			// (which is used only for binding porposes)
			_playlist.canPlayPreviousTrack = true;
			// Shouldn't change statement
			Assert.assertFalse(_playlist.canPlayPreviousTrack);*/
		}
		
		[Test(async)]
		public function canClearCurrentTrack():void
		{
			// First of all let's set currentTrack property
			_playlist.currentTrack = _track1;
			// Check that track is set
			Assert.assertEquals(_playlist.currentTrack, _track1);
			
			(_playlist as AbstractPlaylist).addEventListener(AbstractPlaylist.TRACK_IS_EMPTY, Async.asyncHandler(this, handleTrackEmpty, ASYNC_TIME, _playlist.currentTrack, handleTimeout));
			// Than clear current track
			_playlist.clearCurrentTrack();
			// now current track should be null
			// also an notification event was dispatched
			// @see #handleTrackEmpty()
			Assert.assertNull(_playlist.currentTrack);
			
		}
		
		[Test]
		public function canReturnPlaylistName():void
		{
			// Playlist should return the name
			Assert.assertNotNull(_playlist.playlistName);
		}

			
		protected function handleTimeout( passThroughData:Object):void
		{
			Assert.fail("Timeout reached before an event. Passed object " + passThroughData.toString());
		}
		
		protected function handleTrackNotInplaylist(event:Event, passThroughData:Object):void
		{
			Assert.assertEquals(passThroughData, _trackWhichIsNotInPlaylist);
			(_playlist as AbstractPlaylist).removeEventListener(AbstractPlaylist.TRACK_NOT_IN_PLAYLIST, handleTrackNotInplaylist);
		}
		
		protected function handleTrackEmpty(event:Event, passThroughData:Object):void
		{
			// Handles track empty notification.
			Assert.assertEquals(passThroughData, _track1);
		}
		
		
		protected function handleTrackListIsEmpty(event:Event, passThroughData:Object):void
		{
			Assert.assertEquals(passThroughData, _track1);
		}
		
		
		/**
		 * Creates track object 
		 * @param artist track artist
		 * @param album track album
		 * @param name track name
		 * @param location track location
		 * @return ITrack
		 * 
		 */
		private function createTrack(artist:String, album:String, name:String, location:String):ITrack
		{
			var track:Track = new Track();
			track.album = album;
			track.artist = artist;
			track.name = name;
			track.location = location;
			
			return track;
		}
		
		private function fillPlaylist():void
		{
			_playlist.clear();
			_playlist.addTrack(_track1);
			_playlist.addTrack(_track2);
			_playlist.addTrack(_track3);
		}
	}
}